
/**
 * @file fr_device_rtc.c
 *
 * @author tangzheng
 */

/*********************
 *      INCLUDES
 *********************/
/* Standard includes. */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "fr30xx.h"
#include "FreeRTOS.h"
#include "lvgl.h"
#include "fr_device_rtc.h"
#include "fr_watch.h"


/*********************
 *      DEFINES
 *********************/

#define RTC_DEBUG(fmt,arg...)   printf("[RTC]"fmt,##arg)


/**********************
 *      TYPEDEFS
 **********************/




/**********************
 *  STATIC PROTOTYPES
 **********************/


/**********************
 *  STATIC VARIABLES
 **********************/
#define BLE_BASETIMECNT_MASK   ((uint32_t)0xFFFFFFFF)	//((uint32_t)0x4FFFFFF)

uint32_t system_rtc_tick = 0;
uint32_t last_ke_time;


/**********************
 *  VARIABLES
 **********************/
const unsigned char g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

time_rtc_t rtc_time = {
	.ucYear = 2023,
	.ucMonth = 10,
	.ucDate = 1,
	.ucHour = 12,
	.ucMinute = 0,
	.ucSecond = 0,
};

time_zone_t gSysTimeZone = {
	.h = 8,
	.m = 0,
};

static uint32_t sys_utc_time;
/**********************
 *      MACROS
 **********************/



/**********************
 *   EXTERN FUNCTIONS
 **********************/



/**********************
 *   FUNCTIONS
 **********************/
unsigned char applib_dt_is_leap_year(unsigned short year)
{
	if((year % 400) == 0)
	{
		return 1;
	}
	else if((year % 100) == 0)
	{
		return 0;
	}
	else if((year % 4) == 0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}


unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year)
{
	if((month == 0) || (month > 12))
	{
		return g_day_per_mon[1] + applib_dt_is_leap_year(year);
	}

	if(month != 2)
	{
		return g_day_per_mon[month - 1];
	}
	else
	{
		return g_day_per_mon[1] + applib_dt_is_leap_year(year);
	}
}


unsigned int CalcWeekday(time_rtc_t time)
{

	char century_code, year_code, month_code, day_code;
	int week = 0;
	century_code = year_code = month_code = day_code = 0;
	if(time.ucMonth == 1 || time.ucMonth == 2)
	{
		century_code = (time.ucYear - 1) / 100;
		year_code = (time.ucYear - 1) % 100;
		month_code = time.ucMonth + 12;
		day_code = time.ucDate;
	}
	else
	{
		century_code = time.ucYear / 100;
		year_code = time.ucYear % 100;
		month_code = time.ucMonth;
		day_code = time.ucDate;
	}	

	week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * (month_code + 1) / 10 + day_code - 1;
	week = week > 0 ? (week % 7) : ((week % 7) + 7);
	return week;

}


unsigned int utc_time_to_sec(time_rtc_t* currTime)
{

	unsigned short i;
	unsigned int no_of_days = 0;
	int utc_time;

	if(currTime->ucYear < UTC_BASE_YEAR)
	{
		return 0;
	}

	/* year */
	for(i = UTC_BASE_YEAR; i < currTime->ucYear; i++)
	{
		no_of_days += (DAY_PER_YEAR +  applib_dt_is_leap_year(i));
	}

	/* month */
	for(i = 1; i < currTime->ucMonth; i++)
	{
		no_of_days += applib_dt_last_day_of_mon((unsigned char) i, currTime->ucYear);
	}

	/* day */
	no_of_days += (currTime->ucDate - 1);


#if 0
	/* sec */
	//utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int)(currTime->ucHour * SEC_PER_HOUR +
	//                                                                    currTime->ucMinute * SEC_PER_MIN + currTime->ucSecond);
	utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int)((currTime->ucHour-8) * SEC_PER_HOUR +
	                                                                    currTime->ucMinute * SEC_PER_MIN + currTime->ucSecond);                                                                    
#else
	utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int)(currTime->ucHour * SEC_PER_HOUR +
	                                                                    currTime->ucMinute * SEC_PER_MIN + currTime->ucSecond); 
	utc_time -=  (gSysTimeZone.h * 3600 + gSysTimeZone.m * 60);
#endif
                                                                
	return utc_time;
}


void utc_sec_to_time(unsigned int utc_sec, time_rtc_t* result)
{
	int sec, day;
	unsigned short y;
	unsigned char m;
	unsigned short d;
	//unsigned char dst;

#if 0
	if(daylightSaving)
	{
		utc_sec += SEC_PER_HOUR;
	}
#endif

	utc_sec = utc_sec + gSysTimeZone.h * 3600 + gSysTimeZone.m * 60;

	/* hour, min, sec */
	/* hour */
	sec = utc_sec % SEC_PER_DAY;
	result->ucHour = sec / SEC_PER_HOUR;

	/* min */
	sec %= SEC_PER_HOUR;
	result->ucMinute = sec / SEC_PER_MIN;

	/* sec */
	result->ucSecond = sec % SEC_PER_MIN;

	/* year, month, day */
	/* year */
	/* year */
	day = utc_sec / SEC_PER_DAY;
	for(y = UTC_BASE_YEAR; day > 0; y++)
	{
		d = (DAY_PER_YEAR + applib_dt_is_leap_year(y));
		if(day >= d)
		{
			day -= d;
		}
		else
		{
			break;
		}
	}

	result->ucYear = y;

	for(m = 1; m < MONTH_PER_YEAR; m++)
	{
		d = applib_dt_last_day_of_mon(m, y);
		if(day >= d)
		{
			day -= d;
		}
		else
		{
			break;
		}
	}

	result->ucMonth = m;
	result->ucDate = (unsigned char)(day + 1);

	//result->DayIndex = applib_dt_dayindex(result->ncYear, result->ucMonth, result->ucDate);
}


unsigned char  system_time_set_time_zone(time_zone_t set)
{
	if(gSysTimeZone.h == set.h && gSysTimeZone.m == set.m)
	{
		return 0;
	}

	gSysTimeZone = set;
	return 1;
}


void system_time_set(time_rtc_t set)
{
	rtc_time = set;
}


time_rtc_t *system_time_get(void)
{
	return &rtc_time;
}


time_zone_t *system_time_get_timeZone(void)
{
	return &gSysTimeZone;
}

//date & time
bool CalcDoYear(uint16_t ucYear)
{
	if((ucYear % 400 == 0)
		||((ucYear % 4 == 0) && (ucYear % 100 != 0)))
	{
		return  1;		//run nian
	}
	return 0;
}

uint8_t CalcMaxDate(time_rtc_t time)
{
	uint8_t dates;
	switch(time.ucMonth)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			dates = 31;
			break;

		case 2:
			if(CalcDoYear(time.ucYear))
				dates = 29;	//run nian
			else
				dates = 28;
			break;
		case 4:
		case 6:
		case 9:
		case 11:
			dates = 30;
			break;
	}

	return dates;
}


uint32_t system_get_curr_time(void)
{
	return portGET_RUN_TIME_COUNTER_VALUE();
	//return system_rtc_tick;
}


static uint32_t get_sys_ke_basetime(void)
{
	uint32_t cur_base_time = system_get_curr_time();
    uint32_t diff;
    if(cur_base_time >= last_ke_time)
        diff = cur_base_time - last_ke_time;
    else
        diff = (BLE_BASETIMECNT_MASK - last_ke_time) + cur_base_time + 1;

	return diff;
}

void dev_rtc_time_init(void)
{

	if(sync_cm3_data.time.ucYear < 2023)
		sys_utc_time = utc_time_to_sec(&rtc_time);
	else
		sys_utc_time = utc_time_to_sec(&sync_cm3_data.time);

    last_ke_time = system_get_curr_time();

}

unsigned int get_sys_utc_time(void)
{
	return sys_utc_time;
}

void fr_system_update_utc_time(time_rtc_t *cur_time)
{
	sys_utc_time = utc_time_to_sec(cur_time);
}

void rtc_running(void)
{

	uint32_t diff = get_sys_ke_basetime();
    if( diff > 1000 )
    {
		uint32_t temp_time_value=0;
		temp_time_value = diff / 1000;
		last_ke_time += temp_time_value*1000;
		//if( last_ke_time > BLE_BASETIMECNT_MASK)
		//	last_ke_time -= (BLE_BASETIMECNT_MASK+1);
		
		sys_utc_time += temp_time_value;

		utc_sec_to_time(sys_utc_time,&sync_cm3_data.time);
	}

}



